import { GeneralManager, } from '../Modified027Editor/ModifiedStaticAPI';
import { SpawnManager,SpawnInfo, } from '../Modified027Editor/ModifiedSpawn';
import { PlayerManagerExtesion, } from '../Modified027Editor/ModifiedPlayer';
import { ModifiedCameraSystem,CameraModifid,CameraSystemData, } from '../Modified027Editor/ModifiedCamera';
import { Bezier } from "../tool/Bezier";
import { Constants } from "../tool/Constant";
import { Tween } from "../tool/Tween";
import { util } from "../tool/Utils";
import { EmitSheet, ModuleMotionC, Motion, MotionSheet } from "./ModuleMotion";

type Vector3Like = { x: number; y: number; z: number };

export class ModuleDisplayC extends ModuleC<ModuleDisplayS, null> {
    onFrameChanged: Action1<number> = new Action1();

    private playing: boolean = false;
    private currentFrame = 0;
    private md: ModuleMotionC;
    private currentContext: Motion;
    private obbGo: mw.GameObject;

    private currentLogicThreadID: number;

    private currentDisplayRate = 1;

    displayObj: mw.Character;

    private defaultHeight: number;

    private playedAreaEffect: boolean = false;
    private playedAreaAudio: boolean = false;

    private defaultMoveSpeed: number = 0;

    private playerBaseFov: number;

    private camera: Camera;

    private playerChar: mw.Character;

    private touch: mw.TouchInput;
    private lastLoc: mw.Vector2;

    private levitateRemainFrame: number;
    private invisibleRemainFrame: number;

    private currentCameraTween: Tween<unknown>;

    private skyBoxOriginalColor: mw.LinearColor;

    private emitObjectPool: EmitObject[] = [];

    private skyBox: Skybox;

    async onStart() {
        this.md = ModuleService.getModule(ModuleMotionC);
        this.currentLogicThreadID = setInterval(this.logicUpdate.bind(this), Constants.LogicFrameInterval * 1000);

        this.displayObj = <mw.Character>await GameObject.asyncFindGameObjectById("FA9233A7");
        this.resetCharacterData();

        this.levitateRemainFrame = 0;

        this.playerChar = Player.localPlayer.character;
        ModifiedCameraSystem.setCameraFollowTarget(this.displayObj);
        // 矛 49178
        // 剑 29045
        let weapon = await SpawnManager.wornAsyncSpawn("34657");
        this.displayObj.attachToSlot(weapon, mw.HumanoidSlotType.RightHand);
        weapon.localTransform.position = (new mw.Vector(0, 0, 0));
        weapon.localTransform.rotation = (new mw.Rotation(0, 0, 0));

        this.localPlayer.character.setVisibility(mw.PropertyStatus.Off);
        
        this.obbGo = SpawnManager.modifyPoolSpawn("B1B8C796", mwext.GameObjPoolSourceType.Scene);
        this.obbGo.setVisibility(mw.PropertyStatus.Off);

        this.playerBaseFov = Number(Camera.currentCamera.fov);

        this.camera = Camera.currentCamera;
        this.camera.springArm.collisionEnabled = false;
        this.camera.positionMode = mw.CameraPositionMode.PositionFixed;
        ModifiedCameraSystem.followTargetEnable = false;

        this.touch = new mw.TouchInput();
        // this.touch.setPlayerController();
        this.touch.onTouchBegin.add(this.onTouchBegin.bind(this));
        this.touch.onTouchMove.add(this.onTouchMove.bind(this));

        this.binKeyboardEvent();

        // this.skyBox = GameObject.findGameObjectById("2A5037CC46166B6FD5B9BE8546472FAD") as mw.SkyBox;
        // this.skyBoxOriginalColor = this.skyBox.skyDomeHorizontalTint.clone();
        // this.skyBoxOriginalColor = LinearColor.white
    }

    private resetCharacterData() {
        this.defaultHeight = this.displayObj.worldTransform.position.z;
        this.defaultMoveSpeed = this.displayObj.maxWalkSpeed;
    }

    onTouchMove(index: number, loc: mw.Vector2) {
        let vec = this.lastLoc.clone().subtract(loc);
        let trans = this.camera.worldTransform.clone().clone();
        trans.rotation.z -= vec.x * 0.1;
        trans.rotation.y += vec.y * 0.1;

        this.camera.worldTransform = trans;
        this.lastLoc = loc.clone();
    }

    onTouchBegin(index: number, loc: mw.Vector2) {
        this.lastLoc = loc;
    }

    onUpdate(dt: number) {
        this.displacementUpdate();

        this.emitObjectUpdate();

        // 模拟下落
        if (this.levitateRemainFrame == 0 && this.displayObj.worldTransform.position.z > this.defaultHeight) {
            this.displayObj.worldTransform.position = this.displayObj.worldTransform.position.clone().add(new mw.Vector(0, 0, -10));
        }
    }

    play(context: Motion) {
        this.currentContext = context;
        this.playing = true;
        this.currentFrame = 0;
    }

    changeFrameRate(rate: number) {
        rate = Math.max(0.05, Math.min(4, rate));

        this.currentDisplayRate = rate;
        this.displayObj.maxWalkSpeed = this.defaultMoveSpeed * rate;
        clearInterval(this.currentLogicThreadID);
        this.currentLogicThreadID = setInterval(this.logicUpdate.bind(this), Constants.LogicFrameInterval * 1000 * (1 / rate));
    }

    resetPosition() {
        this.displayObj.worldTransform.position = new mw.Vector(0, 0, this.defaultHeight);
    }

    resetControlCharacter(guid: string): boolean {
        let character = <mw.Character>GameObject.findGameObjectById(guid);
        if (!character) return false;
        this.displayObj = character;
        this.resetCharacterData();
        return true;
    }

    private logicUpdate() {
        // emit 行为
        for (let i = this.emitObjectPool.length - 1; i >= 0; i--) {
            let emit = this.emitObjectPool[i];
            if (!emit.stage) continue;

            emit.onLogicUpdate();

            if (emit.lifeFrame > emit.emit.aliveFrame) {
                emit.dispose();
            }
        }

        if (!this.playing) return;

        if (this.currentFrame >= this.currentContext.motionSheets.length - 1) {
            this.stop();
            return;
        }

        let sheet = this.currentContext.motionSheets[this.currentFrame];

        if (sheet.eff && sheet.eff.guid && sheet.eff.transform && sheet.eff.transform.length == 9) {
            this.playEffectByData(sheet);
        }

        if (sheet.anim && sheet.anim.guid && sheet.anim.count) {
            if (!AssetUtil.assetLoaded(sheet.anim.guid)) {
                AssetUtil.asyncDownloadAsset(sheet.anim.guid);
            }
            let time = sheet.anim.count * Constants.LogicFrameInterval * (1 / this.currentDisplayRate);
            this.displayPlayerPlayAnimation(sheet.anim.guid, time);
        }

        if (sheet.sound) {
            mw.SoundService.playSound(sheet.sound.guid);
        }

        if (sheet.obb && sheet.obb.transform && sheet.obb.transform.length == 9) {
            this.obbGo.setVisibility(mw.PropertyStatus.On);

            let loc = new mw.Vector(sheet.obb.transform[0], sheet.obb.transform[1], sheet.obb.transform[2] + this.defaultHeight);
            loc.x += this.displayObj.worldTransform.position.x;
            loc.y += this.displayObj.worldTransform.position.y;

            this.obbGo.worldTransform.position = loc;
            this.obbGo.worldTransform.rotation = new mw.Rotation(sheet.obb.transform[3], sheet.obb.transform[4], sheet.obb.transform[5]);
            this.obbGo.worldTransform.scale = new mw.Vector(sheet.obb.transform[6], sheet.obb.transform[7], sheet.obb.transform[8]);

            // 击中音效
            if (sheet.obb.soundID && (this.playedAreaAudio == false || this.currentContext.areaEffectOnce)) {
                mw.SoundService.playSound(sheet.obb.soundID);
                this.playedAreaAudio = true;
            }
            // 击中特效
            if (sheet.obb.effectID && (this.playedAreaEffect == false || this.currentContext.areaEffectOnce)) {
                let scale = mw.Vector.one;
                if (sheet.obb.effectScale && sheet.obb.effectScale.length == 3) {
                    scale.x = sheet.obb.effectScale[0];
                    scale.y = sheet.obb.effectScale[1];
                    scale.z = sheet.obb.effectScale[2];
                }
                let effectPlayID = GeneralManager.rpcPlayEffectAtLocation(sheet.obb.effectID, this.obbGo.worldTransform.position, 1, undefined, scale);
                if (sheet.obb.effectColor) {
                    EffectService
                        .getEffectById(effectPlayID)
                        .then((effObj) => {
                            effObj.setColor('Color',mw.LinearColor.colorHexToLinearColor(sheet.obb.effectColor));
                        });
                }
                this.playedAreaEffect = true;
            }
        } else {
            this.obbGo.setVisibility(mw.PropertyStatus.Off);
        }

        if (sheet.emit) {
            this.buildEmitObject(sheet.emit);
        }

        if (sheet.levitate) { 
            this.levitateRemainFrame = sheet.levitate;
        }

        if (sheet.flashRange) {
            this.displayObj.worldTransform.position = this.displayObj.worldTransform.position.clone().add(new mw.Vector(sheet.flashRange, 0, 0));
        }

        if (sheet.cameraTransform) {
            let dataTrans = sheet.cameraTransform;
            let trans = this.camera.localTransform.clone();
            trans.position = new mw.Vector(dataTrans.pos[0], dataTrans.pos[1], dataTrans.pos[2]);
            trans.rotation = new mw.Rotation(dataTrans.rot[0], dataTrans.rot[1], dataTrans.rot[2]);
            this.camera.localTransform = trans;
        }  

        if (sheet.cameraLerpTransform) {
            if (this.currentCameraTween && this.currentCameraTween.isPlaying()) {
                this.currentCameraTween.stop();
            }

            let dataTrans = sheet.cameraLerpTransform;
            let camWorldTransform = this.camera.worldTransform.clone();

            let startLoc = camWorldTransform.position.clone();
            let startRot = camWorldTransform.rotation.clone();

            let playerPosition = this.displayObj.worldTransform.position.clone();
            let playerForward = this.displayObj.worldTransform.getForwardVector();
            let playerRight = this.displayObj.worldTransform.getRightVector();
            let playerUp = this.displayObj.worldTransform.getUpVector();

            let targetLocalPosition = new mw.Vector(dataTrans.pos[0], dataTrans.pos[1], dataTrans.pos[2]);

            let targetLoc = this.vector2World(targetLocalPosition, playerPosition, playerForward, playerRight, playerUp);
            let targetRot = new mw.Rotation(dataTrans.rot[0], dataTrans.rot[1], dataTrans.rot[2]);

            this.currentCameraTween = new Tween({ v: 0 })
                .to({ v: 1 }, dataTrans.during * Constants.LogicFrameInterval * 1000 * this.currentDisplayRate)
                .onUpdate((obj) => {
                    let trans = new mw.Transform();
                    trans.position = mw.Vector.lerp(startLoc, targetLoc, obj.v);
                    trans.rotation = mw.Rotation.lerp(startRot, targetRot, obj.v);
                    this.camera.worldTransform = trans;
                })
                .start();
        }

        if (sheet.cameraTransform) {
            let dataTrans = sheet.cameraTransform;

            let playerPosition = this.displayObj.worldTransform.position.clone();
            let playerForward = this.displayObj.worldTransform.getForwardVector();
            let playerRight = this.displayObj.worldTransform.getRightVector();
            let playerUp = this.displayObj.worldTransform.getUpVector();

            let targetLocalPosition = new mw.Vector(dataTrans.pos[0], dataTrans.pos[1], dataTrans.pos[2]);

            let trans = new mw.Transform();
            trans.position = this.vector2World(targetLocalPosition, playerPosition, playerForward, playerRight, playerUp);
            trans.rotation = new mw.Rotation(dataTrans.rot[0], dataTrans.rot[1], dataTrans.rot[2]);
            this.camera.worldTransform = trans;
        }

        if (sheet.skyBoxColor && sheet.skyBoxColor.horizontalTint && sheet.skyBoxColor.sbDuring) {
            new Tween({ v: 0 })
                .to({ v: 1 }, sheet.skyBoxColor.sbDuring * Constants.LogicFrameInterval * 1000)
                .onUpdate((obj) => {
                    let r = util.lerp(this.skyBoxOriginalColor.r, sheet.skyBoxColor.horizontalTint[0], obj.v);
                    let g = util.lerp(this.skyBoxOriginalColor.g, sheet.skyBoxColor.horizontalTint[1], obj.v);
                    let b = util.lerp(this.skyBoxOriginalColor.b, sheet.skyBoxColor.horizontalTint[2], obj.v);
                    // this.skyBox.skyDomeHorizontalTint = new mw.LinearColor(r, g, b, 1);
                })
                .start();
        }

        if (sheet.skyBoxResetDuring) {
            // let currentColor = this.skyBox.skyDomeHorizontalTint.clone();
            let currentColor = LinearColor.white
            new Tween({ v: 0 })
                .to({ v: 1 }, sheet.skyBoxResetDuring * Constants.LogicFrameInterval * 1000)
                .onUpdate((obj) => {
                    let r = util.lerp(currentColor.r, this.skyBoxOriginalColor.r, obj.v);
                    let g = util.lerp(currentColor.g, this.skyBoxOriginalColor.g, obj.v);
                    let b = util.lerp(currentColor.b, this.skyBoxOriginalColor.b, obj.v);
                    // this.skyBox.skyDomeHorizontalTint = new mw.LinearColor(r, g, b, 1);
                })
                .start();
        }

        if (sheet.invisibleDuring) {
            this.invisibleRemainFrame = sheet.invisibleDuring;
        }

        this.levitateRemainFrame = Math.max(0, this.levitateRemainFrame - 1);

        if (this.invisibleRemainFrame && this.invisibleRemainFrame > 0) {
            this.displayObj.setVisibility(mw.PropertyStatus.Off);
            this.invisibleRemainFrame = Math.max(0, this.invisibleRemainFrame - 1);
        } else {
            this.displayObj.setVisibility(mw.PropertyStatus.On);
        }

        this.currentFrame++;
        this.onFrameChanged.call(this.currentFrame);
    }

    getCameraRelevantLocationFromPlayer(): [mw.Vector, mw.Rotation] {
        let trans = this.camera.worldTransform.clone();

        let resultLoc = trans.position.clone().subtract(this.displayObj.worldTransform.position);
        let resultRot = trans.rotation.clone();

        return [resultLoc, resultRot];
    } 

    addJump() {
        this.displayObj.addImpulse(new mw.Vector(0, 0, 600), false);
    }

    private async playEffectByData(sheet: MotionSheet) {
        let pos = new mw.Vector(sheet.eff.transform[0], sheet.eff.transform[1], sheet.eff.transform[2]);
        let rot = new mw.Rotation(sheet.eff.transform[3], sheet.eff.transform[4], sheet.eff.transform[5]);
        let sca = new mw.Vector(sheet.eff.transform[6], sheet.eff.transform[7], sheet.eff.transform[8]);

        let effectID: number;
   
        // 原地放
        if (sheet.eff.socket == -1) {
            let playerPos = this.displayObj.worldTransform.position
            // 是否为投影特效
            if(sheet.eff.projection == 1){
                let endPosition = this.displayObj.worldTransform.position.clone()
                endPosition.z -= 1000
                let landChecker = QueryUtil.lineTrace(this.displayObj.worldTransform.position,endPosition,true,true)
                let landIndex = landChecker.findIndex(result=>{
                    if (result.gameObject.name != 'SM_Ground') return false;
                    return true
                })
                if(landIndex != -1){
                    playerPos.z = landChecker[landIndex].position.z
                }
            }
            let offset = new mw.Vector(playerPos.x + sheet.eff.transform[0],playerPos.y + sheet.eff.transform[1],playerPos.z + sheet.eff.transform[2])

            effectID = GeneralManager.rpcPlayEffectAtLocation(sheet.eff.guid, offset, 1, rot, sca);
        }
        // 槽位放
        else {
            effectID = GeneralManager.rpcPlayEffectOnPlayer(sheet.eff.guid, this.displayObj as mw.Character, sheet.eff.socket || mw.HumanoidSlotType.Root, 1, pos, rot, sca);
        }

        if (effectID && sheet.eff.color) {
            let effObj = await EffectService.getEffectById(effectID);
            let col = mw.LinearColor.colorHexToLinearColor(sheet.eff.color);
            effObj.setColor('Color', col)
        }
    }

    private async displayPlayerPlayAnimation(guid: string, time: number) {
        if (!mw.AssetUtil.assetLoaded(guid)) await mw.AssetUtil.asyncDownloadAsset(guid);
        PlayerManagerExtesion.loadAnimationExtesion(this.displayObj, guid, false)
        PlayerManagerExtesion.rpcPlayAnimationLocally(this.displayObj, guid, time, 1)
    }

    private displacementUpdate() {
        if (!this.playing) return;

        let sheet = this.currentContext.motionSheets[this.currentFrame];

        if (!sheet.displacement) return;

        if (sheet.displacement.length != 3) {
            return;
        }

        let movePos = sheet.displacement;
        let x = movePos[0] * Constants.LPBalance() * this.currentDisplayRate;
        let y = movePos[1] * Constants.LPBalance() * this.currentDisplayRate;
        let z = movePos[2] * Constants.LPBalance() * this.currentDisplayRate;

        let pos = new mw.Vector(x, y, z);
        this.displayObj.worldTransform.position = this.displayObj.worldTransform.position.clone().add(pos);
    }

    private emitObjectUpdate() {
        for (let emitObject of this.emitObjectPool) {
            if (emitObject.stage) emitObject.onPerformantUpdate(this.currentDisplayRate);
        }
    }

    private stop() {
        this.playing = false;
        this.currentFrame = 0;
        this.onFrameChanged.call(0);
        this.playedAreaEffect = false;
        this.playedAreaAudio = false;
        this.currentContext = undefined;
        this.levitateRemainFrame = 0;
        this.invisibleRemainFrame = 0;
        this.obbGo.setVisibility(mw.PropertyStatus.Off);
        Camera.currentCamera.fov = this.playerBaseFov;
        if (this.currentCameraTween) {
            this.currentCameraTween.stop();
            this.currentCameraTween = undefined;
        }
    }

    cameraFollow() {
        let trans = this.camera.localTransform.clone().clone();
        trans.position = new mw.Vector(-400, 0, 190);
        trans.rotation = new mw.Rotation(0, -20, 0);
        this.camera.localTransform = trans;
        this.camera.springArm.length = 100;
        ModifiedCameraSystem.followTargetEnable = true;
    }

    lockCamera() {
        ModifiedCameraSystem.followTargetEnable = false;
    }

    private cameraTranslate(dir: mw.Vector) {
        let trans = this.camera.worldTransform.clone().clone();
        trans.position = trans.position.add(dir);
        this.camera.worldTransform = trans;
    }

    private buildEmitObject(emit: EmitSheet) {
        let obj: EmitObject;
        for (let emitObject of this.emitObjectPool) {
            if (!emitObject.stage) {
                obj = emitObject;
                break;
            }
        }
        if (!obj) {
            obj = new EmitObject();
            this.emitObjectPool.push(obj);
        }
        obj.show(emit, this.displayObj);
    }

    private binKeyboardEvent() {
        InputUtil.onKeyPress(mw.Keys.W, () => {
            let loc = this.camera.worldTransform.clone().position.clone();
            let addLoc = GeneralManager.modifyGetShootDir(this.playerChar, loc, 1).normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.W, () => {
            let loc = this.camera.worldTransform.clone().position.clone();
            let addLoc = GeneralManager.modifyGetShootDir(this.playerChar, loc, 1).normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
        // 拍照模式移动镜头位置
        InputUtil.onKeyPress(mw.Keys.S, () => {
            let loc = this.camera.worldTransform.clone().position.clone();
            let addLoc = GeneralManager.modifyGetShootDir(this.playerChar, loc, 1).normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.S, () => {
            let loc = this.camera.worldTransform.clone().position.clone();
            let addLoc = GeneralManager.modifyGetShootDir(this.playerChar, loc, 1).normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        // 拍照模式移动镜头位置
        InputUtil.onKeyPress(mw.Keys.A, () => {
            let addLoc = this.camera.worldTransform.getRightVector().normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.A, () => {
            let addLoc = this.camera.worldTransform.getRightVector().normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        // 拍照模式移动镜头位置
        InputUtil.onKeyPress(mw.Keys.D, () => {
            let addLoc = this.camera.worldTransform.getRightVector().normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.D, () => {
            let addLoc = this.camera.worldTransform.getRightVector().normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
        // 拍照模式移动镜头位置
        InputUtil.onKeyPress(mw.Keys.Q, () => {
            let addLoc = this.camera.worldTransform.getUpVector().normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.Q, () => {
            let addLoc = this.camera.worldTransform.getUpVector().normalized.multiply(-20);
            this.cameraTranslate(addLoc);
        });
        // 拍照模式移动镜头位置
        InputUtil.onKeyPress(mw.Keys.E, () => {
            let addLoc = this.camera.worldTransform.getUpVector().normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
        InputUtil.onKeyDown(mw.Keys.E, () => {
            let addLoc = this.camera.worldTransform.getUpVector().normalized.multiply(20);
            this.cameraTranslate(addLoc);
        });
    }

    private vector2World(vector: Vector3Like, worldPosition: mw.Vector, forward: mw.Vector, right: mw.Vector, up: mw.Vector): mw.Vector {
        return new mw.Vector(vector.x * forward.x + vector.y * right.x + vector.z * up.x + worldPosition.x, vector.x * forward.y + vector.y * right.y + vector.z * up.y + worldPosition.y, vector.x * forward.z + vector.y * right.z + vector.z * up.z + worldPosition.z);
    }
}

export class EmitObject {
    effectID: number;
    targetObject: mw.GameObject;
    areaObject: mw.GameObject;
    lifeFrame: number;
    emit: EmitSheet;
    owner: mw.GameObject;
    stage: boolean;
    // 法术场生成位置
    startPosition: mw.Vector;

    show(emit: EmitSheet, owner: mw.GameObject) {
        this.emit = emit;
        mw.HumanoidSlotType.RightHand;
        this.lifeFrame = 0;
        this.targetObject = SpawnManager.modifyPoolSpawn("Anchor");
        this.areaObject = SpawnManager.modifyPoolSpawn("B1B8C796", mwext.GameObjPoolSourceType.Scene);
        this.areaObject.worldTransform.scale = this.emit.areaScale ? new mw.Vector(this.emit.areaScale[0], this.emit.areaScale[1], this.emit.areaScale[2]) : mw.Vector.one;

        // 播放特效
        let scale = emit.scale ? new mw.Vector(emit.scale[0], emit.scale[1], emit.scale[2]) : undefined;
        let rotation = emit.rotationOffset ? new mw.Rotation(emit.rotationOffset[0], emit.rotationOffset[1], emit.rotationOffset[2]) : undefined;
        this.effectID = GeneralManager.rpcPlayEffectOnGameObject(this.emit.effectID, this.targetObject, 0, undefined, rotation, scale);

        if(this.emit.color){
            EffectService.getEffectById(this.effectID).then(obj=>{
                if(obj){
                    obj.setColor('Color', mw.LinearColor.colorHexToLinearColor(this.emit.color))
                }
            })
        }

        this.owner = owner;
        let offset = emit.positionOffset ? new mw.Vector(emit.positionOffset[0], emit.positionOffset[1], emit.positionOffset[2]) : mw.Vector.zero;
        this.startPosition = owner.worldTransform.position.clone().add(offset);
        this.targetObject.worldTransform.position = this.startPosition;
        this.stage = true;
        this.lifeFrame = 0;

        let dir = new mw.Vector(-1, 1, 0);
        // let dir = new mw.Vector(-1,0,1)
        for (let i = 0; i < 5; i++) {
            let r = ((2 * Math.PI) / 5) * i;
            let res = this.rotateUpByAnyDir(dir, r);
            console.error(`旋转:${res.x.toFixed(2)} , ${res.y.toFixed(2)} , ${res.z.toFixed(2)}`);
        }
    }

    onLogicUpdate() {
        this.lifeFrame += 1;
    }

    onPerformantUpdate(timeRate: number) {
        if (this.emit.trajectoryType == "bezier") {
            this.bezierDisplacement();
            return;
        }
        this.normalDisplacement(timeRate);
    }

    private bezierDisplacement() {
        if (!this.emit.trajectoryArgs) {
            console.error("弹道参数错误!");
            return;
        }

        let args = this.emit.trajectoryArgs.split(",");
        if (args.length != 3) {
            console.error("弹道参数错误!");
            return;
        }

        let delta = this.lifeFrame / this.emit.aliveFrame;
        let t = Number(args[0]);
        let angle = Number(args[1]);
        let length = Number(args[2]);
        let targetPosition = mw.Vector.add(this.owner.worldTransform.position, this.owner.worldTransform.getForwardVector().multiply(this.emit.lockDistance));
        let middlePoint = mw.Vector.lerp(this.startPosition, targetPosition, t);
        let toEndDir = mw.Vector.subtract(this.startPosition, targetPosition).normalized;
        let middleDir = this.rotateUpByAnyDir(toEndDir, angle * 0.01745).multiply(length);
        let middlePosition = mw.Vector.add(middlePoint, middleDir);
        let bezierPosition = Bezier.evaluate_2l(this.startPosition, middlePosition, targetPosition, delta);

        this.targetObject.worldTransform.position = bezierPosition;
        this.areaObject.worldTransform.position = bezierPosition;
    }

    private normalDisplacement(timeRate: number) {
        let gravityData = this.emit.gravity || 0;
        let gravity = (this.lifeFrame / this.emit.aliveFrame) * gravityData;

        let t = new mw.Vector(this.emit.translate[0] * Constants.LPBalance() * timeRate, this.emit.translate[1] * Constants.LPBalance() * timeRate, this.emit.translate[2] * Constants.LPBalance() * timeRate - gravity);
        let newPos = this.targetObject.worldTransform.position.clone().add(t);
        this.targetObject.worldTransform.position = newPos;
        this.areaObject.worldTransform.position = newPos;
    }

    dispose() {
        EffectService.stop(this.effectID);
        // 命中特效
        if (this.emit.hitEffect) {
            let scale = this.emit.hitEffectScale ? new mw.Vector(this.emit.hitEffectScale[0], this.emit.hitEffectScale[1], this.emit.hitEffectScale[2]) : mw.Vector.one;

            GeneralManager.rpcPlayEffectAtLocation(this.emit.hitEffect, this.targetObject.worldTransform.position, 1, undefined, scale);
        }
        mwext.GameObjPool.despawn(this.targetObject);
        mwext.GameObjPool.despawn(this.areaObject);
        this.stage = false;
    }

    private rotateUpByAnyDir(n: mw.Vector, r: number): mw.Vector {
        let cos = Math.cos;
        let sin = Math.sin;
        let l3x = n.x * n.z * (1 - cos(r)) - n.y * sin(r);
        let l3y = n.z * n.y * (1 - cos(r)) + n.x * sin(r);
        let l3z = cos(r) + n.z * n.z * (1 - cos(r));
        return new mw.Vector(l3x, l3y, l3z);
    }
}

export class ModuleDisplayS extends ModuleS<ModuleDisplayC, null> {}
